<?php

namespace App\Kuafu\Config\Service;

use App\Exceptions\BaseException;
use App\Kuafu\Activity\Enum\ActivityEnum;
use App\Kuafu\Activity\Model\ActivityModel;
use App\Kuafu\Config\Enum\ConfigCacheEnum;
use App\Kuafu\Config\Enum\ConfigCodeEnum;
use App\Kuafu\Config\Exceptions\ConfigException;
use App\Kuafu\Config\Model\ConfigModel;
use App\Kuafu\Config\Validate\ConfigValidate;
use App\Kuafu\Product\Enum\ProductCacheEnum;
use App\Kuafu\User\Service\AuthService;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use App\Kuafu\Base\Service\BaseService;

class ConfigService extends BaseService
{
    /**
     * 新增配置
     * @param string $name
     * @param string $key
     * @param string $value
     * @param string $type
     * @param string $remark
     * @return bool
     * @throws ConfigException
     */
    public static function addConfig(string $name, string $key, string $value, string $type, string $remark)
    {
        if (!ConfigModel::addData($name, $key, $value, $type, $remark)) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_DB_ADD);
        }

        Cache::forget(ConfigCacheEnum::getConfigType($type));

        return true;
    }

    public static function setConfig(Request $request)
    {
        $configId = (int)$request->post('configId');
        $name     = (string)$request->post('name');
        $key      = (string)$request->post('key');
        $value    = (string)$request->post('value');
        $type     = (string)$request->post('type');
        $remark   = (string)$request->post('remark');

        $valid = ConfigValidate::setConfig($request);
        if ($valid) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_PARAM, $valid);
        }

        $oriConfig = ConfigModel::query()->find($configId);

        if (!ConfigModel::setData($configId, $name, $key, $value, $type, $remark)) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_DB_SET, $valid);
        }

        Cache::forget(ConfigCacheEnum::getConfigType($oriConfig->type));
        Cache::forget(ConfigCacheEnum::getConfigType($type));

        return true;
    }

    public static function delConfig(Request $request, $configId)
    {
        $configId = (int)$configId;
        $config   = ConfigModel::query()->where('id', $configId)->first();
        if (!$config) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_ID_NULL);
        }

        if (!ConfigModel::delData($configId)) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_DB_DEL);
        }

        Cache::forget(ConfigCacheEnum::getConfigType($config->type));

        return true;
    }

    public static function getConfigById(Request $request, $configId)
    {
        $configId = (int)$configId;
        $data     = ConfigModel::getDataById($configId);
        return $data ? $data->toArray() : null;
    }

    public static function getConfigList(Request $request)
    {
        $name     = (string)$request->get('name');
        $key      = (string)$request->get('key');
        $type     = (string)$request->get('type');
        $pageSize = (int)$request->get('pageSize', 20);
        $pageNum  = (int)$request->get('pageNum', 1);

        $query = ConfigModel::getDataPage($name, $key, $type, $pageSize, $pageNum);
        $data  = [
            'pageNum'   => $query->currentPage(),
            'pageSize'  => $query->perPage(),
            'pageCount' => ceil($query->total() / $query->perPage()),
            'count'     => $query->total(),
            'lists'     => $query->items(),
        ];

        return $data;
    }

    public static function listByTypeAndKey(string $type, string $key = ""): array
    {
        if (!$type) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_PARAM_TYPE);
        }

        $lists = ConfigModel::getDataPageByType($type);

        // 筛选key
        if ($key) {
            $lists = collect($lists)->filter(function ($item) use ($key) {
                if ($item['key'] == $key) {
                    return true;
                }

                return false;
            })->values()->toArray();
        }

        return array_column($lists, 'value', 'key');
    }

    public static function getConfigInfoByValue($condition, $field)
    {
        return ConfigModel::getConfigInfoByCondition($condition, $field);
    }

    public static function setAppNotify($data)
    {
        $configModels = ConfigModel::query()
                                   ->where('key', 'appNotify')
                                   ->update(['value' => json_encode($data, JSON_UNESCAPED_UNICODE)]);
        return ['result' => $configModels];
    }

    /**
     * 获取自定义套餐分类Id
     *
     * @return array
     */
    public static function getPackageCategoryId()
    {
        return Cache::remember('getPackageCategoryId', 60, function () {
            return ConfigModel::query()
                              ->where('key', 'customProductCategoryId')
                              ->where("type", "merchant")
                              ->first()->value;
        });
    }

    /**
     * 获取自定义套商品最大上线数量
     *
     * @return array
     */
    public static function getCustomProductMaxOnlineCount()
    {
        return Cache::remember('getCustomProductMaxOnlineCount', 600, function () {
            return ConfigModel::query()
                              ->where('key', 'customProductMaxOnlineCount')
                              ->where("type", "customerProduct")
                              ->first()->value;
        });
    }

    /**
     * 最大必点数数量
     *
     * @return void
     */
    public static function getMustProductMaxCount(){
        return Cache::remember('getMustProductMaxCount', getSwitchCacheTime(99999), function () {
            return ConfigModel::query()
                              ->where('key', 'mustProductMaxCount')
                              ->where("type", "customerProduct")
                              ->first()->value;
        }) ?? 2;
    }

    /**
     * 所有的names
     * @return array
     */
    public static function allModules(): array
    {
        return ConfigModel::query()->where('type', '!=', '')->select('type')->groupBy('type')->get()->map(function ($item) {
            return [
                'id'   => $item->type,
                'name' => $item->type,
            ];
        })->toArray();
    }

    public static function index(string $module, string $name, int $pageSize, int $pageNum): array
    {
        $paginator = ConfigModel::query()
                            ->with('createdUser')
                            ->with('updatedUser')
                            ->when($module, function ($query) use ($module) {
                                $query->where('type', $module);
                            })
                            ->when($name, function ($query) use ($name) {
                                $query->where('key', $name);
                            })
                            ->orderByDesc('id')
                            ->paginate($pageSize, ['*'], 'page', $pageNum);

        return [
            'count'    => $paginator->total(),
            'list'     => $paginator->map(function (ConfigModel $configModel) {

                $type = 'string';
                if (is_int($configModel->value)) {
                    $type = 'int';
                } elseif (is_array(json_decode($configModel->value, true))) {
                    $type = 'json';
                }

                return [
                    'createdAt'   => $configModel->createdAt->toDateTimeString(),
                    'createdBy'   => (string)optional($configModel->createdUser)->username,
                    'updatedAt'   => $configModel->updatedAt->toDateTimeString(),
                    'updatedBy'   => (string)optional($configModel->updatedUser)->username,
                    'description' => $configModel->remark,
                    'id'          => $configModel->id,
                    'module'      => $configModel->type,
                    'name'        => $configModel->key,
                    'type'        => $type,
                    'value'       => $configModel->value,
                ];
            }),
            'pageNum'  => (int)$pageNum,
            'pageSize' => (int)$pageSize,
        ];
    }

    public static function save(int $id, string $description, $value, string $module, string $name): int
    {
        if ($id) {
            return ConfigModel::query()->where('id', $id)->update([
                'remark'       => $description,
                'value'        => $value,
                'updatedByUid' => AuthService::getUserId(),
            ]);
        }

        $config = ConfigModel::query()->where(['type' => $module, 'key' => $name])->first();
        if ($config) {
            throw new ConfigException(ConfigCodeEnum::ERR_CONFIG_ADD_REPEAT);
        }

        ConfigModel::query()->create([
            'type'   => $module,
            'key'    => $name,
            'remark' => $description,
            'value'  => $value,
            'name'   => $description,
        ]);

        return 1;
    }

    /**
     * 商家自选广告图数量
     * @return int
     */
    public static function getBannerMaxCount(): int
    {
        return Cache::remember('getBannerMaxCount', getSwitchCacheTime(86400), function () {
                return ConfigModel::query()
                                  ->where('key', 'bannerMaxCount')
                                  ->where("type", "bannerMaxCount")
                                  ->value('value');
            }) ?? 3;
    }

    /**
     * 获取配置信息
     *
     * @param string $type
     * @param string $key
     * @param int $cacheTime
     * @return array|mixed|void
     * @throws BaseException
     */
    public static function getConfigDetail(string $type, string $key, int $cacheTime = 0)
    {
        try {
            $configDetailFunc = function () use ($type, $key) {
                $configDetail = ConfigModel::query()
                                           ->where("type", $type)
                                           ->where("key", $key)
                                           ->first();
                if (!$configDetail) {
                    throw new Exception("获取配置失败");
                }

                return [
                    "type" => $type,
                    "key"   => $key,
                    "value"  => jsonToArr($configDetail->getOriginal("value"), $configDetail->getOriginal("value"))
                ];
            };

            if ($cacheTime > 0) {
                return Cache::remember(
                    vsprintf("%s:%s:%s:%d", [__FUNCTION__, $type, $key, $cacheTime]),
                    $cacheTime,
                    function () use ($type, $key, $configDetailFunc) {
                        return $configDetailFunc();
                    }
                );
            } else {
                return $configDetailFunc();
            }
        } catch (Exception $exception) {
            handleException($exception, "获取配置数据失败");
        }
    }

    /**
     * 支付统计类型配置
     * @return array
     */
    public static function getPayUnionConfig(): array
    {
        return Cache::remember('getPayUnionConfig', getSwitchCacheTime(3600), function () {
            return json_decode(ConfigModel::query()
                                          ->where('key', 'payUnionConfig')
                                          ->where("type", "merchant")
                                          ->value('value') ?? '', true);
        });
    }
}
